﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ThreeByte.ActiveDeck.Config;
using System.Collections.ObjectModel;
using ThreeByte.ActiveDeck.Controls;
using System.Xml.Linq;
using ThreeByte.Media;
using System.Collections.Specialized;

namespace ThreeByte.ActiveDeck.Content
{
    /// <summary>
    /// Interaction logic for CategoriesPreview.xaml
    /// </summary>
    public partial class CategoriesPreview : UserControl, IPreviewControl
    {
        private readonly CategoriesConfig cConfig;

        public PageConfig Config { get; set; }

        public CategoriesPreview(CategoriesConfig config) {
            InitializeComponent();
            config.PruneEmptyItems();
            cConfig = config;
            Config = config;
            DataContext = cConfig;
            config.Categories.CollectionChanged += new NotifyCollectionChangedEventHandler(Categories_CollectionChanged);
            config.Words.CollectionChanged += new NotifyCollectionChangedEventHandler(Words_CollectionChanged);
            RefreshCategories(config.Categories);
            RefreshWords(config.Words);
            RefreshTheme();
            config.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(config_PropertyChanged);
        }

        void config_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
            if (e.PropertyName == "Theme") {
                RefreshTheme();
            } else if(e.PropertyName == "Words") {
                RefreshWords(cConfig.Words);
            }
        }

        void RefreshTheme() {
            string resPath = ((CategoriesConfig)DataContext).Theme;
            this.Resources.MergedDictionaries.Clear();
            if(!(string.IsNullOrWhiteSpace(resPath))) {
                Uri dictPath = new Uri(resPath, UriKind.RelativeOrAbsolute);
                ResourceDictionary newDict = Application.LoadComponent(dictPath) as ResourceDictionary;
                this.Resources.MergedDictionaries.Add(newDict);
            }
        }

        void Words_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
            RefreshWords((ObservableCollection<Word>)sender);
        }

        private void RefreshWords(ObservableCollection<Word> words) {
            int count = Math.Min(words.Count, WordFloatCanvas.Children.Count);
            for(int i = 0; i < count; i++) {
                TextBlock wordBlock = (TextBlock)(WordFloatCanvas.Children[i]);
                wordBlock.Text = words[i].Text;
            }
        }

        void Categories_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
            RefreshCategories((ObservableCollection<Category>)sender);
        }

        private void RefreshCategories(ObservableCollection<Category> categories) {
            CategoryGrid.Children.Clear();
            CategoryGrid.ColumnDefinitions.Clear();

            int column = 0;
            foreach (Category c in categories) {
                if(column > 0) {
                    //Add Spacer column
                    CategoryGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(20) });
                    column++; //Increment the column again
                }
                CategoryGrid.ColumnDefinitions.Add(new ColumnDefinition());
                WordBucket newBucket = new WordBucket();
                newBucket.SetBinding(WordBucket.CategoryProperty, new Binding("Text") { Source = c });
                newBucket.SetValue(Grid.ColumnProperty, column);
                CategoryGrid.Children.Add(newBucket);
                column++;
            }


        }

        //Happens on Dispatcher Thread
        public PresentationPageConfiguration GetPageConfiguration() {
            XNamespace ns = Service.ServiceConfiguration.NAMESPACE;

            PresentationPageConfiguration newPage = new PresentationPageConfiguration();

            XElement pageNode = cConfig.GetPresentationXml("Categories");
            
            pageNode.Add(cConfig.GetGradingConfig());

            //Disable the Interactive Elements
            LayerRenderer.Hide();
            //Snap the Background
            this.UpdateLayout();
            GraphicResource backgroundResource = new GraphicResource(ImageUtil.SaveToBitmapSource(LayoutRoot, ImageUtil.DefaultPortraitSize), null, ImageType.JPEG);
            newPage.Resources[backgroundResource.ID] = backgroundResource;
            XElement backgroundNode = new XElement(ns + "BackgroundImage", new XAttribute("ResourceID", backgroundResource.ID));
            pageNode.Add(backgroundNode);

            //Enable the Interactive Elements
            LayerRenderer.Show();
            this.UpdateLayout();

            //Foreach word bucket
            int value = 0;

            foreach (UIElement el in CategoryGrid.Children) {
                WordBucket w = el as WordBucket;
                if (w == null) {
                    continue;
                }

                value++;
                XElement categoryElement = new XElement(ns + "Category");
                categoryElement.Add(new XAttribute("Value", value));

                Point wPos = w.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                categoryElement.Add(new XAttribute("Top", (int)Math.Round(wPos.Y)));
                categoryElement.Add(new XAttribute("Left", (int)Math.Round(wPos.X)));
                categoryElement.Add(new XAttribute("Width", (int)Math.Round(w.ActualWidth)));
                categoryElement.Add(new XAttribute("Height", (int)Math.Round(w.ActualHeight)));

                //Snap the Bucket Cap/category title
                GraphicResource categoryResource = new GraphicResource(ImageUtil.SaveToBitmapSource(w.CapGrid));
                newPage.Resources[categoryResource.ID] = categoryResource;
                XElement bucketCapElement = new XElement(ns + "BucketCap");
                Point capPos = w.CapGrid.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                bucketCapElement.Add(new XAttribute("Width", (int)Math.Round(w.CapGrid.ActualWidth)));
                bucketCapElement.Add(new XAttribute("Height", (int)Math.Round(w.CapGrid.ActualHeight)));
                XElement bucketCapImage = new XElement(ns + "Image", new XAttribute("ResourceID", categoryResource.ID));
                bucketCapElement.Add(bucketCapImage);
                categoryElement.Add(bucketCapElement);

                //Snap the Bucket Edge
                GraphicResource bucketEdgeResource = new GraphicResource(ImageUtil.SaveToBitmapSource(w.BucketEdge));
                newPage.Resources[bucketEdgeResource.ID] = bucketEdgeResource;
                XElement bucketEdgeElement = new XElement(ns + "BucketEdge");
                Point edgePos = w.BucketEdge.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                bucketEdgeElement.Add(new XAttribute("Top", (int)Math.Round(edgePos.Y)));
                bucketEdgeElement.Add(new XAttribute("Left", (int)Math.Round(edgePos.X)));
                bucketEdgeElement.Add(new XAttribute("Width", (int)Math.Round(w.BucketEdge.ActualWidth)));
                bucketEdgeElement.Add(new XAttribute("Height", (int)Math.Round(w.BucketEdge.ActualHeight)));
                XElement bucketEdgeImage = new XElement(ns + "Image", new XAttribute("ResourceID", bucketEdgeResource.ID));
                bucketEdgeElement.Add(bucketEdgeImage);
                categoryElement.Add(bucketEdgeElement);

                pageNode.Add(categoryElement);
            }

            //Locate the Words
            XElement wordsElement = new XElement(ns + "Words");
            value = 0;
            foreach (TextBlock tb in WordFloatCanvas.Children) {
                XElement startPosElement = new XElement(ns + "StartPosition");
                Point tbPos = tb.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                startPosElement.Add(new XAttribute("Top", (int)Math.Round(tbPos.Y + (tb.ActualHeight / 2.0))));
                startPosElement.Add(new XAttribute("Left", (int)Math.Round(tbPos.X + (tb.ActualWidth / 2.0))));

                wordsElement.Add(startPosElement);
            }


            int id = 0;
            foreach (Word w in cConfig.Words) {
                id++;
                XElement newWord = new XElement(ns + "Word", new XAttribute("ID", id), new XAttribute("Text", w.Text));
                wordsElement.Add(newWord);
            }
            wordsElement.Add(new XAttribute("Count", id));
            wordsElement.Add(new XAttribute("Color", "#FFEEEEEE"));
            pageNode.Add(wordsElement);

            //Locate the ActionButton
            {
                XElement buttonElement = new XElement(ns + "Button");
                buttonElement.Add(ActionButton.Action.ToXml());

                Point buttonPos = ActionButton.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                buttonElement.Add(new XAttribute("Top", (int)Math.Round(buttonPos.Y)));
                buttonElement.Add(new XAttribute("Left", (int)Math.Round(buttonPos.X)));
                buttonElement.Add(new XAttribute("Width", (int)Math.Round(ActionButton.ActualWidth)));
                buttonElement.Add(new XAttribute("Height", (int)Math.Round(ActionButton.ActualHeight)));

                //Snap the Button
                LayerRenderer.SetActive();
                GraphicResource buttonOnResource = new GraphicResource(ImageUtil.SaveToBitmapSource(ActionButton));
                newPage.Resources[buttonOnResource.ID] = buttonOnResource;
                XElement imageOnNode = new XElement(ns + "ImageOn", new XAttribute("ResourceID", buttonOnResource.ID));
                buttonElement.Add(imageOnNode);
                this.UpdateLayout();

                //Snap the Off Button
                LayerRenderer.SetInactive();
                GraphicResource buttonOffResource = new GraphicResource(ImageUtil.SaveToBitmapSource(ActionButton));
                newPage.Resources[buttonOffResource.ID] = buttonOffResource;
                XElement imageOffNode = new XElement(ns + "ImageOff", new XAttribute("ResourceID", buttonOffResource.ID));
                buttonElement.Add(imageOffNode);
                pageNode.Add(buttonElement);
                LayerRenderer.Show();
                this.UpdateLayout();
            }

            //Locate the ResetButton
            {
                XElement buttonElement = new XElement(ns + "Button");
                buttonElement.Add(new XElement(ns + "Action", new XAttribute("Type", "Reset")));

                Point buttonPos = ResetButton.TransformToAncestor(LayoutRoot).Transform(new Point(0, 0));
                buttonElement.Add(new XAttribute("Top", (int)Math.Round(buttonPos.Y)));
                buttonElement.Add(new XAttribute("Left", (int)Math.Round(buttonPos.X)));
                buttonElement.Add(new XAttribute("Width", (int)Math.Round(ResetButton.ActualWidth)));
                buttonElement.Add(new XAttribute("Height", (int)Math.Round(ResetButton.ActualHeight)));

                //Snap the Button
                LayerRenderer.SetActive();
                GraphicResource buttonOnResource = new GraphicResource(ImageUtil.SaveToBitmapSource(ResetButton));
                newPage.Resources[buttonOnResource.ID] = buttonOnResource;
                XElement imageOnNode = new XElement(ns + "ImageOn", new XAttribute("ResourceID", buttonOnResource.ID));
                buttonElement.Add(imageOnNode);
                this.UpdateLayout();

                //Snap the Off Button
                LayerRenderer.SetInactive();
                GraphicResource buttonOffResource = new GraphicResource(ImageUtil.SaveToBitmapSource(ResetButton));
                newPage.Resources[buttonOffResource.ID] = buttonOffResource;
                XElement imageOffNode = new XElement(ns + "ImageOff", new XAttribute("ResourceID", buttonOffResource.ID));
                buttonElement.Add(imageOffNode);
                pageNode.Add(buttonElement);
                LayerRenderer.Show();
                this.UpdateLayout();
            }

            newPage.ConfigXml = pageNode;
            return newPage;
        }


    }
}
